﻿// <copyright file="RootDirectoryContainer.cs" company="Sinclair Community College">
// Copyright 2010 Sinclair Community College
// </copyright>
// <originalAuthor>Patrick S. Seymour (patrick.seymour@gmail.com)</originalAuthor>

namespace SinclairCC.AppV
{
    using System;
    using System.IO;

    /// <summary>
    /// This container provides a permanent storage for the root directory of an App-V volume.
    /// </summary>
    /// <remarks>
    /// This container provides a starting point to enumerate an App-V volume. 
    /// </remarks>
    public class RootDirectoryContainer : Container
    {
        private StorageBlockInfoTable storageBlockTable;
        private System.Collections.ObjectModel.Collection<_DIRECTORY_STRUCT_PRIMARY> childDirectories;

        public RootDirectoryContainer(BinaryReader fileReader)
            : base(fileReader)
        {
            this.childDirectories = new System.Collections.ObjectModel.Collection<_DIRECTORY_STRUCT_PRIMARY>();
            this.storageBlockTable = null;
            this.ReadContainer(fileReader);
        }

        /// <summary>
        /// Reads the actual data for this container from the file.
        /// </summary>
        protected void ReadContainer(BinaryReader fileReader)
        {
            /*
             * If the data storage type has the FORMAT_BLOCKMAP flag, then immediately after the
             * common header will be a _DIRECTORY_STRUCT_PRIMARY structure which describes the
             * root directory. After this structure, there can be one or more StorageBlockInfo
             * structures which point to the actual storage blocks that contain the rest of the
             * _DIRECTORY_STRUCT_PRIMARY objects, which are children of the root directory.
             * 
             * If the data storage type has the FORMAT_INLINE flag, any child _DIRECTORY_STRUCT_PRIMARY
             * will be inline within this container after the root _DIRECTORY_STRUCT_PRIMARY.
             */

            /*
            if ((this.Header.StorageType & DataStorageType.FORMAT_BLOCKMAP) == DataStorageType.FORMAT_BLOCKMAP)
            {
                this.storageBlockTable = new StorageBlockInfoTable(fileReader);
            }
            else if ((this.Header.StorageType & DataStorageType.FORMAT_INLINE) == DataStorageType.FORMAT_INLINE)
            {
                this.ReadDirectoryStructs(fileReader);
            }
            */

            _DIRECTORY_STRUCT_PRIMARY rootDirStruct = new _DIRECTORY_STRUCT_PRIMARY(fileReader);

            if ((this.Header.StorageType & DataStorageType.FORMAT_BLOCKMAP) == DataStorageType.FORMAT_BLOCKMAP)
            {
                // TODO: Need a PKG file that has its root directory in block map format in order to test this code.
                this.storageBlockTable = new StorageBlockInfoTable(fileReader);
            }
            else if ((this.Header.StorageType & DataStorageType.FORMAT_INLINE) == DataStorageType.FORMAT_INLINE)
            {
                this.ReadDirectoryStructs(fileReader);
            }
        }

        private void ReadDirectoryStructs(BinaryReader reader)
        {
            _DIRECTORY_STRUCT_PRIMARY dirStruct;
            do
            {
                dirStruct = new _DIRECTORY_STRUCT_PRIMARY(reader);
                if (dirStruct.StructureType != 0)
                {
                    this.childDirectories.Add(dirStruct);
                }
            }
            while ((reader.BaseStream.Length > reader.BaseStream.Position) /* && (dirStruct.StructureType != 0) */ );
        }

        public StorageBlockInfoTable StorageBlockTable
        {
            get { return this.storageBlockTable; }
        }

        public System.Collections.ObjectModel.Collection<_DIRECTORY_STRUCT_PRIMARY> ChildDirectories
        {
            get { return this.childDirectories; }
        }

        /*
        public void Process(uint containerSize, uint storageBlockSize, System.IO.BinaryReader fileReader)
        {
            long position = fileReader.BaseStream.Position;
            foreach (StorageBlockInfo sbi in this.storageBlockTable)
            {
                long offset = sbi.GetOffset(containerSize, storageBlockSize);
                if (offset != -1)
                {
                    // Seek to the container's offset.
                    fileReader.BaseStream.Seek(offset, SeekOrigin.Begin);
                    byte[] storageBlockBuffer = new byte[storageBlockSize];
                    int bytesRead = fileReader.Read(storageBlockBuffer, 0, storageBlockBuffer.Length);

                    MemoryStream storageBlockStream = new MemoryStream(storageBlockBuffer, false);
                    System.IO.BinaryReader storageBlockReader = new System.IO.BinaryReader(storageBlockStream);

                    this.ReadDirectoryStructs(storageBlockReader);

                    storageBlockReader.Close();
                    storageBlockStream.Close();
                    storageBlockStream.Dispose();
                }
            }
            fileReader.BaseStream.Seek(position, SeekOrigin.Begin);
        }
        */
    }
}
